﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.Fabric;
using System.Threading;
using System.Net.Sockets;
using System.Reflection;

namespace ActorRuntimeManager
{

        
    public partial class MainForm : Form
    {
        private static volatile string s_connectionString = "127.0.0.1:19000"; // Change if you connect to Azure
        private static ConnectionMode s_connectionMode = ConnectionMode.Local;
        private static FabricClient s_client;
        private static string s_appBase = Environment.CurrentDirectory + "\\" + @"ActorManifest\ApplicationPackages";
        private static string s_containerName = "imagestore";
        private static string s_accountName = "";
        private static string s_accountKey = "";
        private Task m_runtimeMonitorTask;
        private bool m_localFabricClusterDeployed = false;
        private bool m_localFabricClusterConnected = false;
        private const string s_imageStoreConnectionStringFormat = @"xstore:DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};Container={2}";

        // These are various directory paths / file locations that need to be read from the registry once WinFab is installed
        private const string WindowsFabricRegKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Fabric";
        private static string FabricDataRoot;
        private static string FabricBinRoot;
        private static string FabricCodePath;
        private static string s_fabricHostPath;
        private static string s_imageStoreClientExe;
        private static string s_localImageStore;
        private static string s_fullManifestName;

        private static void ReadFabricPaths()
        {
            FabricDataRoot = ((string)Registry.GetValue(WindowsFabricRegKey, "FabricDataRoot", string.Empty));
            if (FabricDataRoot != null)
            {
                FabricDataRoot = FabricDataRoot.TrimEnd('\\'); // remove any trailing backslash
                FabricBinRoot = ((string)Registry.GetValue(WindowsFabricRegKey, "FabricBinRoot", string.Empty)).TrimEnd('\\'); // remove any trailing backslash
                FabricCodePath = ((string)Registry.GetValue(WindowsFabricRegKey, "FabricCodePath", string.Empty)).TrimEnd('\\'); // remove any trailing backslash
                s_fabricHostPath = Path.Combine(FabricBinRoot, "FabricHost.exe");
                s_imageStoreClientExe = "\"" + Path.Combine(FabricCodePath, "ImageStoreClient.exe") + "\"";
                s_localImageStore = "file:" + Path.Combine(FabricDataRoot, "ImageStore").TrimEnd('\\');
                s_fullManifestName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "WinFab", "DevEnv-FiveNodes.xml");
            }
        }

        public static ActorAccountingInfo[] s_actorAccountingInfo = new ActorAccountingInfo[] {
            new ActorAccountingInfo {AppName="ListActorApp", FabricAppName="fabric:/actor/list", ReplicaType="ListActorReplica"},
            new ActorAccountingInfo {AppName="DictionaryActorApp", FabricAppName="fabric:/actor/dictionary", ReplicaType="DictionaryActorReplica"},
            new ActorAccountingInfo {AppName="EmptyActorApp", FabricAppName="fabric:/actor/adhoc", ReplicaType="EmptyActorReplica"},
            new ActorAccountingInfo {AppName="StatelessActorApp", FabricAppName="fabric:/actor/stateless", ReplicaType="StatelessActorService"},
            new ActorAccountingInfo {AppName="ActorGatewayApp", FabricAppName="fabric:/actor/gateway", ReplicaType="ActorGatewayService"}
        };

        public static string AppNameFromFabricAppName(string fabricAppName)
        {
            return s_actorAccountingInfo.Where(ai => ai.FabricAppName.Equals(fabricAppName)).Select(ai => ai.AppName).FirstOrDefault();
        }

        public static string FabricAppNameFromAppName(string appName)
        {
            return s_actorAccountingInfo.Where(ai => ai.AppName.Equals(appName)).Select(ai => ai.FabricAppName).FirstOrDefault();
        }

        internal static FabricClient Client
        {
            get
            {
                if (s_client == null) s_client = new FabricClient(s_connectionString);
                return s_client;
            }
        }

        // Constructor
        public MainForm()
        {
            InitializeComponent();
            if(!VerifyPrerequisites())
                Environment.Exit(-1);
            CheckForRuntimeInstallation();
            this.labelConnectionMode.Text = s_connectionMode.ToString();
            this.labelConnectionString.Text = s_connectionString;
            this.Invalidate();
            m_runtimeMonitorTask = Task.Factory.StartNew(() =>
            {
                var client = new TcpClient();
                while (true)
                {
                    var parts = s_connectionString.Split(':');
                    var server = parts[0];
                    var port = Int32.Parse(parts[1]);

                    try
                    {
                        client.Connect(server, port);
                        LocalFabricClusterDeployed = true;
                        client.Close();
                        client = new TcpClient();
                    }
                    catch (Exception)
                    {
                        LocalFabricClusterDeployed = false;
                    }
                    int sleepDuration = Debugger.IsAttached ? 15000 : 1000;
                    Thread.Sleep(sleepDuration);
                }
            });

        }

        private bool VerifyPrerequisites()
        {
            // Check OS version
            var osVersion = Environment.OSVersion;
            if (Environment.OSVersion.Version < new Version(6, 1))
            {
                MessageBox.Show("Your OS must be at least Windows 7", "ERROR");
                return false;
            }

            // Check for 64-bitness
            if (!Environment.Is64BitOperatingSystem && Environment.Is64BitProcess)
            {
                MessageBox.Show("You must have 64-bit operating system and 64-bit process", "ERROR");
                return false;
            }

            // Check for presence of the right version of the Azure SDK
            // Actor Runtime v2.1 requires Azure SDK 2.1.
            // The Actor Runtime hasn't been tested with other versions of the Azure SDK, but might work (maybe).
            // Deployments to Azure using the ActorFxAzureCluster project did not work, and required upgrading the
            // project to the 2.1 version of the Azure SDK (in project properties) as well as using VS 2012 instead of VS 2013.
            // The Azure SDK's seem to be side-by-side, except for this registry key.
            // Note: if you're testing this, this program looks at the 32 bit registry, not 64 bit one.
            Version expectedVersion = new Version(2, 1);   // If you change this, update the URL below in our second MessageBox.
            var emulatorVersion = (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Azure Emulator", "FullVersion", null);
            if (emulatorVersion == null || !emulatorVersion.StartsWith(expectedVersion.Major + "." + expectedVersion.Minor + "."))
            {
                Version emulatorVer = null;
                if (emulatorVersion != null)
                    emulatorVer = Version.Parse(emulatorVersion);
                if (emulatorVer != null && emulatorVer.CompareTo(expectedVersion) > 0)
                {
                    var res = MessageBox.Show(
                        String.Format("The Actor Runtime has only been tested with Azure SDK v{0}.{1}.  You have version {2}.{3} installed.  This has not been tested and may not work at all.  Continue anyways?",
                        expectedVersion.Major, expectedVersion.Minor, emulatorVer.Major, emulatorVer.Minor), 
                        "Azure SDK version is more recent than we expect", MessageBoxButtons.YesNo);
                    if (res != DialogResult.Yes)
                        return false;
                }
                else
            {
                    MessageBox.Show(String.Format("You must first install Azure SDK v{0}.{1}.  You can find it at http://www.microsoft.com/en-us/download/details.aspx?id=38797", 
                        expectedVersion.Major, expectedVersion.Minor));
                return false;
            }
            }

            return true;
        }

        #region Runtime installation logic

        // Checks whether or not the actor runtime has been installed
        public void CheckForRuntimeInstallation()
        {
            var rtInstalled = RuntimeInstalled();

            // Check to see whether windows fabric has been installed
            //var fabricRoot = Environment.GetEnvironmentVariable("FabricRoot");
            if (rtInstalled)
            {
                OnRuntimeInstalled();
            }
        }

        private void OnRuntimeInstalled()
        {
            ReadFabricPaths();
            this.labelRtInstalled.ForeColor = Color.Green;
            this.labelRtInstalled.Text = "Installed";
            this.buttonInstallRt.Enabled = false;
            this.buttonDeployLocalCluster.Enabled = s_connectionMode == ConnectionMode.Local;
            this.buttonScour.Enabled = s_connectionMode == ConnectionMode.Local;
        }

        private bool RuntimeInstalled()
        {
            return (Registry.GetValue(WindowsFabricRegKey, "FabricVersion", null) != null);
        }

        // Handles installation of actor runtime
        private void buttonInstallRt_Click(object sender, EventArgs e)
        {
            var userName = Environment.UserName;
            var domainName = Environment.UserDomainName;

            if (Directory.Exists("WinFab"))
            {
                EulaForm eula = new EulaForm();
                eula.ShowDialog();
                if (!eula.Accepted)
                {
                    MessageBox.Show("We cannot install the Actor Runtime software unless you accept the licensing agreement (EULA)");
                    return;
                }

                //MessageBox.Show(String.Format("Using userName={0}, domainName={1}", userName, domainName));
                //var args = String.Format("/i /quiet /passive WinFab\\WindowsFabric.msi PRINCIPALDOMAIN={0} PRINCIPALUSER={1}", domainName, userName);
                var args = "/i WinFab\\WindowsFabric.2.1.40.9493.msi /qb";
                var p = Process.Start("msiexec.exe", args);
                p.WaitForExit();
                //p.ExitCode;
                //ServiceLoginDialog dlg = new ServiceLoginDialog();
                //dlg.Show();
                //this.textBoxSpecialInstructions.Text = "";
                //var lines = new string[] {
                //    "In the services window:",
                //    "  Right-click on \"Windows Fabric Host Service\" and choose \"Properties\"",
                //    "  Choose the \"Log On\" tab",
                //    "  Enter your password (twice)",
                //    "  Click \"OK\"",
                //    "  Close the window"};
                //this.textBoxSpecialInstructions.Lines = lines;
                //MessageBox.Show("In the services window:\nRight-click on \"Windows Fabric Host Service\" and choose \"Properties\"\nChoose the \"Log On\" tab\nEnter your password\nClick \"OK\" and close the window");
                
                //p = Process.Start("Services.msc");
                //MessageBox.Show("DON'T DISMISS THIS WINDOW UNTIL YOU HAVE COMPLETED THE INSTRUCTIONS BELOW!\n\n" +
                //                "In the services window that was just popped up, do the following:\n" +
                //                " (1) Right-click on the \"Windows Fabric Host Service\" and choose \"Properties\"\n" +
                //                " (2) Choose the \"Log On\" tab\n" +
                //                " (3) Enter your password (twice)\n" +
                //                " (4) Click \"OK\"\n" +
                //                " (5) Don't forget to close the services window\n\n" +
                //                "Once you have completed the above sequence, close this window.", "Special Instructions");
                //p.WaitForExit();
                
                //dlg.Hide();
                //this.textBoxSpecialInstructions.Text = "";
                //Process.Start("msiexec.exe", "/i WinFab\\WindowsFabricSDK.msi");

                if (RuntimeInstalled())
                {
                    OnRuntimeInstalled(); // Probably useless, since we're about to exit.  But good form anyway.
                    MessageBox.Show("The actor runtime has been installed.  At this point in the installation process, you should exit the ActorRuntimeManager and start it again.\n\n",
                                    "ActorRuntimeManager exiting...");
                    Environment.Exit(0);
                }
                else
                {
                    MessageBox.Show("Runtime NOT installed");
                }
            }
            else MessageBox.Show("Could not find WinFab directory");
        }

        #endregion

        #region Local cluster logic

        private bool ClusterCreated()
        {
            return Directory.Exists(Path.Combine(FabricDataRoot, "Node1"));
        }

        /// <summary>
        /// Create or Remove a cluster
        /// </summary>
        /// <param name="operation">Create or Remove</param>
        /// <param name="clusterManifestFullName"></param>
        private void ClusterOperation(string operation, string clusterManifestFullName, ModelessStatusForm statusForm = null)
        {
            var fabricDeployerExe = "\"" + Path.Combine(FabricCodePath, "FabricDeployer.exe") + "\"";
            var args = String.Format("/operation:{0} /cm:\"{1}\"", operation, clusterManifestFullName);

            if (statusForm != null) statusForm.Write("Starting cluster-{0} operation...", operation);
            ProcessStartInfo psi = new ProcessStartInfo(fabricDeployerExe, args);
            //psi.WorkingDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            //psi.RedirectStandardError = true;
            //psi.RedirectStandardOutput = true;
            //psi.UseShellExecute = false;
            //psi.CreateNoWindow = true;
            var proc = Process.Start(psi);
            proc.WaitForExit();
            if (statusForm != null) statusForm.WriteLine(" Done");
        }

        // Property tracking whether or not a local fabric cluster has been deployed
        private bool LocalFabricClusterDeployed
        {
            get { return m_localFabricClusterDeployed; }
            set
            {
                if (m_localFabricClusterDeployed != value)
                {
                    m_localFabricClusterDeployed = value;
                    UpdateLocalFabricClusterInfo();
                    if (value)
                    {
                        buttonScour.Invoke((Action)(() =>
                            {
                                buttonScour.Enabled = false;
                            }));
                        BeginWaitForConnection();
                    }
                    else
                    {
                        // Disable a bunch of buttons if the fabric deployment goes away
                        // And do it via the UI thread
                        buttonProvision.Invoke((Action)(() =>
                            {
                                buttonRefresh.Enabled = false;
                                buttonProvision.Enabled = false;
                                buttonUnprovision.Enabled = false;
                                buttonStopServices.Enabled = false;
                                buttonLaunchActor.Enabled = false;
                                buttonLaunchAlias.Enabled = false;
                                buttonScour.Enabled = true;
                                checkedListBoxActors.Items.Clear();
                                checkedListBoxApplications.Items.Clear();
                            }));
                    }
                }
            }
        }

        // Property tracking whether or not the local fabric cluster is up and receiving connections
        private bool LocalFabricClusterConnected
        {
            get { return m_localFabricClusterConnected; }
            set
            {
                if (m_localFabricClusterConnected != value)
                {
                    m_localFabricClusterConnected = value;
                    UpdateLocalFabricClusterInfo();
                }
            }
        }

        // Takes care of updating the button/text associated with local fabric cluster state
        private void UpdateLocalFabricClusterInfo()
        {
            string message;
            Color color;
            string buttonText;
            bool buttonEnabled;

            if (!LocalFabricClusterDeployed)
            {
                message = "Not Deployed";
                color = Color.Red;
                buttonText = "Deploy";
                buttonEnabled = true;
            }
            else
            {
                if (LocalFabricClusterConnected)
                {
                    message = "Deployed, Connected";
                    color = Color.Green;
                    buttonText = "Undeploy";
                    buttonEnabled = true;
                }
                else
                {
                    message = "Deployed, Connecting...";
                    color = Color.Red;
                    buttonText = "Undeploy";
                    buttonEnabled = false;
                }
            }

            this.labelClusterDeployed.Invoke((Action)(() =>
            {
                labelClusterDeployed.Text = message;
                labelClusterDeployed.ForeColor = color;
                buttonDeployLocalCluster.Enabled = (s_connectionMode == ConnectionMode.Local) && buttonEnabled;
                buttonDeployLocalCluster.Text = buttonText;
            }));
        }

        // When it has been determined that a local fabric cluster has gone from "not deployed" to "deployed",
        // this method is called so that we can know when the local fabric cluster is up and ready to
        // respond to commands.
        //
        // It just checks connection status once per second until the cluster has been determined to be connected.
        public void BeginWaitForConnection()
        {
            Task t = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        FabricClient fc = Client;
                        fc.PropertyManager.NameExistsAsync(new Uri(@"fabric:/WinFabric")).Wait();
                        LocalFabricClusterConnected = true;
                        break;
                    }
                    catch (Exception)
                    {
                        Thread.Sleep(1000);
                    }
                }
            }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

            // Once connection is achieved, refresh the actor app/service info.
            t.ContinueWith(antecedent =>
            {
                label1.Invoke((Action)(() =>
                {
                    RefreshProvisionedActorApps();
                    buttonProvision.Enabled = true;
                    buttonRefresh.Enabled = true;
                }));
            });

        }

        // Handle deployment or undeployment of local fabric cluster
        private void buttonDeployLocalCluster_Click(object sender, EventArgs e)
        {
            ModelessStatusForm statusForm = null;

            try
            {
                if (((Button)sender).Text.Equals("Deploy"))
                {
                    statusForm = new ModelessStatusForm("Cluster Deployment");
                    statusForm.Show();
                    if (!ClusterCreated())
                    {
                        ClusterOperation("Create", s_fullManifestName, statusForm);
                    }
                    else statusForm.WriteLine("Cluster detected, no creation necessary");

                    ProcessStartInfo psi = new ProcessStartInfo();
                    psi.FileName = s_fabricHostPath;
                    psi.Arguments = "-c -activateHidden"; // TODO: Revisit?  Use service instead of console app ("-c")?
                    psi.WorkingDirectory = FabricCodePath;
                    //psi.UseShellExecute = true;
                    Process p = Process.Start(psi);


                }
                else
                {
                    var result = MessageBox.Show(
                                    "Are you sure that you want to bring down the local cluster?",
                                    "Are you sure?",
                                    MessageBoxButtons.OKCancel);
                    if (result == DialogResult.OK)
                    {
                        statusForm = new ModelessStatusForm("Cluster undeployment");
                        statusForm.Show();
                        this.buttonDeployLocalCluster.Enabled = false;


                        Process[] list = null;
                        list = Process.GetProcessesByName("FabricHost");
                        if (list != null && list.Length > 0)
                        {
                            statusForm.Write("Found FabricHost, killing it...");
                            Process p1 = list[0];
                            p1.Kill();
                            while (!p1.HasExited)
                            {
                                Thread.Sleep(500);
                            }
                            statusForm.WriteLine("Done!");
                        }
                        else
                        {
                            statusForm.Close();
                            statusForm = null;
                            MessageBox.Show("Could not find FabricHost process");
                            this.buttonDeployLocalCluster.Enabled = true; // in case they want to try again
                        }
                    }
                }
            }
            finally
            {
                if (statusForm != null) statusForm.Close();
            }
        }

        private void buttonScour_Click(object sender, EventArgs e)
        {
            var result = MessageBox.Show(
                "Scouring wipes all residual application data from your local actor runtime cluster.  It should " +
                "only be called after all actor services have been stopped, all actor apps have been undeployed, and " +
                "the cluster has been undeployed.",
                "Scour Cluster",
                MessageBoxButtons.OKCancel);

            if (result == DialogResult.OK)
            {
                var statusForm = new ModelessStatusForm("Scour");
                statusForm.Show();
                statusForm.WriteLine("Beginning scour operation");

                try
                {
                    ClusterOperation("Remove", s_fullManifestName, statusForm);
                    ClusterOperation("Create", s_fullManifestName, statusForm);
                }
                finally { statusForm.Close(); }
                //var executable = "powershell.exe";
                //string args = "-File WinFab\\LocalClusterOps\\ScourCluster.ps1";
                //Process p1 = Process.Start(executable, args);
            }
        }

        #endregion

        #region Actor app/service logic

        // Refresh the status of deployed actor apps
        private void RefreshProvisionedActorApps()
        {
            checkedListBoxApplications.Items.Clear();
            var appNames = GetDeploymentInfo();
            buttonLaunchActor.Enabled = false;
            buttonLaunchAlias.Enabled = false;
            buttonUnprovision.Enabled = false;
            foreach (var name in appNames)
            {
                checkedListBoxApplications.Items.Add(name);
            }

            RefreshRunningActors();
        }

        // Refresh the status of deployed actor services
        private void RefreshRunningActors()
        {
            checkedListBoxActors.Items.Clear();
            var actorNames = GetDeploymentInfo(getApps: false);
            buttonStopServices.Enabled = false;
            checkBoxSelectAll.Checked = false;
            foreach (var name in actorNames)
            {
                checkedListBoxActors.Items.Add(name);
            }
        }
                


        // Returns an array of the names of currently deployed apps or services
        private string[] GetDeploymentInfo(bool getApps = true) // otherwise, get services
        {
            NameEnumerationResult nameResult = null;
            FabricClient fc = Client;
            List<string> deployedNames = new List<string>();
            Uri baseUri = new Uri("Fabric:/actor");

            // TODO: async/await
            var t = Task.Factory.StartNew(() =>
                {
                    try
                    {
                        do
                        {
                            nameResult = fc.PropertyManager.EnumerateSubNamesAsync(baseUri, nameResult, true).Result;
                            foreach (var name in nameResult)
                            {
                                var s = name.ToString();
                                if ((s.Count(c => c == '/') == 2) == getApps)
                                {
                                    // This is an application, not a service.
                                    deployedNames.Add(s);
                                }
                            }
                        } while (nameResult.HasMoreData);
                    }
                    catch (AggregateException ae)
                    {
                        if (!ae.Flatten().InnerExceptions.Any(ex => ex is FabricElementNotFoundException))
                            throw;
                    }
                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
            t.Wait();

            return deployedNames.ToArray();
        }

        // Initiates the provisioning of an actor app
        private void buttonProvision_Click(object sender, EventArgs e)
        {
            var alreadyDeployedApps = GetDeploymentInfo();
            var candidates = new List<string>();
            if (Directory.Exists(s_appBase))
            {
                var actorAppDirs = Directory.GetDirectories(s_appBase);
                foreach (var name in actorAppDirs)
                {
                    // Don't show Gateway app in local mode.
                    if (name.Contains("ActorGatewayApp") && (s_connectionMode == ConnectionMode.Local)) continue;
                    var localDirName = name.Substring(s_appBase.Length + 1);
                    var instanceName = FabricAppNameFromAppName(localDirName);
                    if(!alreadyDeployedApps.Contains(instanceName))
                    {
                        candidates.Add(localDirName);
                    }
                }
            }

            if (candidates.Count > 0)
            {
                string connectionString = null;
                string imageStoreExecutableName = s_imageStoreClientExe;
                if (s_connectionMode == ConnectionMode.Local)
                {
                    connectionString = s_localImageStore;
                }
                else
                {
                    if (String.IsNullOrWhiteSpace(s_accountName) || String.IsNullOrWhiteSpace(s_containerName) ||
                        String.IsNullOrWhiteSpace(s_accountKey))
                    {
                        MessageBox.Show(this, "For cloud operation, you must specify values for Account Name, Container Name and Account Key");
                        return;
                    }
                    connectionString = String.Format(s_imageStoreConnectionStringFormat, s_accountName, s_accountKey, s_containerName);
                }
                var deployForm = new DeployAppForm(candidates.ToArray(), connectionString, imageStoreExecutableName);
                deployForm.ShowDialog();
                RefreshProvisionedActorApps();
            }
            else MessageBox.Show(this, "All available actor apps have already been deployed");

        }

        // Handles stopping of all checked actor services.
        private void buttonStopServices_Click(object sender, EventArgs e)
        {
            foreach (var item in checkedListBoxActors.CheckedItems)
            {
                Client.ServiceManager.DeleteServiceAsync(new Uri((string)item)).Wait();
            }

            RefreshRunningActors();
        }

        // Handles unprovisioning of all checked actor apps.
        private void buttonUnprovision_Click(object sender, EventArgs e)
        {
            //var baseName = "fabric:/actor/";
            var copiedList = new List<string>();
            foreach (var item in checkedListBoxApplications.CheckedItems)
            {
                var appName = (string)item;
                copiedList.Add(appName);
            }

            foreach(var fabricAppName in copiedList)
            {
                try
                {
                    Client.ApplicationManager.DeleteApplicationAsync(new Uri(fabricAppName)).Wait();
                }
                catch (Exception exc)
                {
                    var baseException = (exc is AggregateException) ? ((AggregateException)exc).GetBaseException() : exc;
                    MessageBox.Show("Exception on application deletion: " + baseException);
                }


                var typeName = AppNameFromFabricAppName(fabricAppName);
                try
                {
                    if (typeName != null)
                    {
                        Client.ApplicationManager.UnprovisionApplicationAsync(typeName, "1.0").Wait();
                    }
                    // if typeName is null, then assume that we are unprovisioning an app alias
                    RefreshProvisionedActorApps();
                }
                catch (Exception exc)
                {
                    var baseException = (exc is AggregateException) ? ((AggregateException)exc).GetBaseException() : exc;
                    MessageBox.Show("Exception on un-provision: " + baseException);
                }
            }
        }

        // Action to take when an actor app is checked/unchecked
        private void checkedListBoxApplications_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            var numChecked = checkedListBoxApplications.CheckedItems.Count;
            if (e.NewValue == CheckState.Checked) numChecked++;
            else numChecked--;

            this.buttonUnprovision.Enabled = (numChecked > 0);
            this.buttonLaunchActor.Enabled = (numChecked == 1);
            buttonLaunchAlias.Enabled = (numChecked == 1);
        }

        // Action to take when an actor service is checked/unchecked
        private void checkedListBoxActors_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            var numChecked = checkedListBoxActors.CheckedItems.Count;
            if (e.NewValue == CheckState.Checked) numChecked++;
            else numChecked--;

            this.buttonStopServices.Enabled = (numChecked > 0);
        }

        private void buttonRefresh_Click(object sender, EventArgs e)
        {
            RefreshRunningActors();
        }

        private void checkBoxSelectAll_CheckedChanged(object sender, EventArgs e)
        {
            var setMe = checkBoxSelectAll.Checked;
            for (int index = 0; index < checkedListBoxActors.Items.Count; index++)
            {
                checkedListBoxActors.SetItemChecked(index, setMe);
            }
        }
        #endregion

        private void buttonChangeConnectionSettings_Click(object sender, EventArgs e)
        {
            var connForm = new ConnectionInformationForm(s_connectionMode, s_connectionString,s_accountName, s_containerName, s_accountKey);
            connForm.ShowDialog();
            if (connForm.OKSelected)
            {
                // TODO: There is probably some synchronization/more careful ordering that needs to occur here
                s_connectionString = connForm.ConnectionString;
                s_connectionMode = connForm.ConnectionMode;
                s_containerName = connForm.ContainerName;
                s_accountName = connForm.AccountName;
                s_accountKey = connForm.AccountKey;
                this.labelConnectionMode.Text = s_connectionMode.ToString();
                this.labelConnectionString.Text = s_connectionString;

                LocalFabricClusterDeployed = false;
                s_client = new FabricClient(s_connectionString);
            }
        }

        private void buttonLaunchActor_Click(object sender, EventArgs e)
        {
            var chosenActorType = (string) checkedListBoxApplications.CheckedItems[0];
            LaunchActorForm launchForm = new LaunchActorForm(Client, chosenActorType);
            launchForm.ShowDialog();
            if (launchForm.Successful) RefreshRunningActors();
        }

        private void buttonLaunchAppAlias_Click(object sender, EventArgs e)
        {
            var chosenActorType = (string)checkedListBoxApplications.CheckedItems[0];
            var appName = AppNameFromFabricAppName(chosenActorType);
            if (appName != null)
            {
                LaunchAppAlias launchForm = new LaunchAppAlias(appName);
                launchForm.ShowDialog();
                if (launchForm.Successful) RefreshProvisionedActorApps();
            }
            else MessageBox.Show("You can only create app aliases from base application types");

        }








    }

    public class ActorAccountingInfo
    {
        public string AppName { get; set; }
        public string FabricAppName { get; set; }
        public string ReplicaType { get; set; }
    }

    public enum ConnectionMode
    {
        Local,
        Cloud
    }
}
